﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System8ToyMC.Plots;
using System8ToyMC;
using System.Linq;
using System.Windows.Controls.DataVisualization.Charting;
using System.Collections.ObjectModel;
using System8Equations;

namespace t_System8ToyMCControls
{
    [TestClass]
    public class t_PlotManager : PresentationTest
    {
        [TestMethod]
        public void TestCTor()
        {
            PlotManager p = new PlotManager();
        }

        [TestMethod]
        [Asynchronous]
        public void TestAddPlot()
        {
            Histogram h = new Histogram();

            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => Assert.AreEqual("n.Total", FindChart(h).Title, "Chart title wasn't set correctly"));
            EnqueueTestComplete();
        }

        [TestMethod]
        public void TestRunWithNoPlots()
        {
            PlotManager p = new PlotManager();
            p.Calculate(NiceS8());
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestSinglePlot()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueConditional(() => FindColumnSeries(h).ItemsSource != null);
            EnqueueConditional(() => (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(49, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length, "Number of bins is wrong"));
            EnqueueCallback(() => Assert.AreEqual(p.Loops,  (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Sum(d => d.Content), "expecting teh number of loops in content!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        public void TestBasicVarManipulation()
        {
            S8Variable s8 = new UniformS8Variable(950) { Path = "n/TotalValue", MaxValue = 1000, MinValue = 900 };
            PlotManager p = new PlotManager();

            Assert.IsFalse(p.HasVariable("n/TotalValue"));
            p.RemoveVaryingVariable("n/TotalValue");
            p.AddVaryingVariable(s8);
            p.RemoveVaryingVariable("n/TotalValue");
        }

        [TestMethod]
        public void TestRemoveAllVars()
        {
            S8Variable s8 = new UniformS8Variable(950) { Path = "n/TotalValue", MaxValue = 1000, MinValue = 900 };
            PlotManager p = new PlotManager();

            Assert.IsFalse(p.HasVariable("n/TotalValue"));
            p.AddVaryingVariable(s8);
            Assert.IsTrue(p.HasVariable("n/TotalValue"));
            p.RemoveAllVaryingVariables();
            Assert.IsFalse(p.HasVariable("n/TotalValue"));
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestRunWithNoPlotsAndVariable()
        {
            PlotManager p = new PlotManager();
            S8Variable s8 = new UniformS8Variable(950) { Path = "n/TotalValue", MaxValue = 1000, MinValue = 900 };

            p.AddVaryingVariable(s8);
            Histogram h = new Histogram();
            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            EnqueueCallback(() => TestPanel.Children.Add(h));
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueConditional(() => data.ItemsSource != null);
            EnqueueConditional(() => (data.ItemsSource as Histogram.BinData[]).Length > 0);
            Func<bool> IsGoodHisto = () =>
            {
                int count = 0;
                foreach (var bin in (data.ItemsSource as Histogram.BinData[]))
                {
                    if (bin.Content > 0)
                    {
                        count++;
                    }
                }
                return count > 3;
            };
            EnqueueCallback(() => Assert.IsTrue(IsGoodHisto(), "Non zero bins are too small!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestCentralValuesOfVaryingVarsUpdated()
        {
            PlotManager p = new PlotManager();
            var s8Vars = NiceS8();
            UniformS8Variable s8 = new UniformS8Variable(s8Vars.n.Total) { Path = "n/TotalValue", MaxValue = s8Vars.n.Total * 1.1, MinValue = s8Vars.n.Total * 0.9 };
            double oldMax = s8.MaxValue;

            ///
            /// Run one calc
            /// 

            p.AddVaryingVariable(s8);
            Histogram h = new Histogram();
            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            EnqueueCallback(() => TestPanel.Children.Add(h));
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));

            EnqueueCallback(() => p.Calculate(s8Vars));
            EnqueueConditional(() => data.ItemsSource != null);
            object oldData = null;
            EnqueueCallback(() => oldData = data.ItemsSource);

            ///
            /// Reset and run a second. Make sure that min/max have changed!
            /// 

            EnqueueCallback(() => s8Vars.n.Total = s8Vars.n.Total * 1.20);
            EnqueueCallback(() => p.Calculate(s8Vars));
            EnqueueConditional(() => data.ItemsSource != oldData);
            EnqueueCallback(() => Assert.AreNotEqual(oldMax, s8.MaxValue, "Expected the max to change when we updated the central value"));
            EnqueueTestComplete();
        }

        [TestMethod]
        public void TestRunVarableVarrying()
        {
            PlotManager p = new PlotManager();
            S8Variable s8 = new UniformS8Variable(950) { Path = "n/TotalValue", MaxValue = 1000, MinValue = 900 };

            p.AddVaryingVariable(s8);


            p.Calculate(NiceS8());
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestFindPlot()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => Assert.AreEqual(h, p.FindPlot("n/TotalValue")));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestRemovePlot()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.RemovePlot("n/TotalValue"));
            EnqueueCallback(() => Assert.IsNull(p.FindPlot("n/TotalValue")));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestRecalculateClearsPlotsFirst()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueConditional(() => FindColumnSeries(h).ItemsSource != null);
            EnqueueConditional(() => (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(49, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length, "Number of bins is wrong"));
            EnqueueCallback(() => Assert.AreEqual(p.Loops, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Sum(d => d.Content), "expecting teh number of loops in content!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestLoops()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            p.Loops = 3500;
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueConditional(() => FindColumnSeries(h).ItemsSource != null);
            EnqueueConditional(() => (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(49, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length, "Number of bins is wrong"));
            EnqueueCallback(() => Assert.AreEqual(p.Loops, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Sum(d => d.Content), "expecting teh number of loops in content!"));
            EnqueueCallback(() => Assert.AreEqual(3500, p.Loops, "Loops change didn't stick!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(5000)]
        public void TestBackgroundThread()
        {
            ///
            /// This is just a stress test...
            /// 

            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.Loops = 3500);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueConditional(() => FindColumnSeries(h).ItemsSource != null);
            EnqueueConditional(() => (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => p.Loops = 3600);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3700);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3800);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3900);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3000);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3100);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3200);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3300);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3400);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueDelay(200);
            EnqueueCallback(() => Assert.AreEqual(49, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length, "Number of bins is wrong"));
            EnqueueCallback(() => Assert.AreEqual(p.Loops, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Sum(d => d.Content), "expecting teh number of loops in content!"));
            EnqueueCallback(() => Assert.AreEqual(3400, p.Loops, "Loops change didn't stick!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        public void TestBatchUpdates()
        {
            Histogram h = new Histogram();
            EnqueueCallback(() => TestPanel.Children.Add(h));
            PlotManager p = new PlotManager();
            EnqueueCallback(() => p.AddPlot1D(h, "n/TotalValue"));
            EnqueueCallback(() => p.Loops = 3500);
            EnqueueCallback(() => p.BeginBatchUpdate());
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueDelay(200);
            EnqueueCallback(() => Assert.IsNull(FindColumnSeries(h).ItemsSource, "No updates should have occured since we are batching things"));
            EnqueueCallback(() => p.Loops = 3600);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3700);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3800);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3900);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3000);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3100);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3200);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3300);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => p.Loops = 3400);
            EnqueueCallback(() => p.Calculate(NiceS8()));
            EnqueueCallback(() => Assert.IsNull(FindColumnSeries(h).ItemsSource, "No updates should have occured since we are batching things"));
            EnqueueCallback(() => p.EndBatchUpdate());
            EnqueueConditional(() => FindColumnSeries(h).ItemsSource != null);
            EnqueueConditional(() => (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(49, (FindColumnSeries(h).ItemsSource as Histogram.BinData[]).Length, "Number of bins is wrong"));
            EnqueueTestComplete();
        }

        /// <summary>
        /// Returns the data that is what goes into the chart
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        ColumnSeries FindColumnSeries(Histogram h)
        {
            var c = FindChart(h);
            if (c == null)
            {
                return null;
            }

            return c.Series[0] as ColumnSeries;
        }

        /// <summary>
        /// Returns the chart in the histogram.
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        Chart FindChart(Histogram h)
        {
            return h.FindName("MainChart") as Chart;
        }


        public System8Equations.S8Equations NiceS8()
        {
            System8Equations.S8Equations eqn = new System8Equations.S8Equations();

            eqn.n.Bottom = 10000;
            eqn.n.Charm = 10000;
            eqn.n.Light = 10000;

            eqn.n1.Bottom = 5000;
            eqn.n1.Charm = 5000;
            eqn.n1.Light = 5000;

            eqn.n2.Bottom = 5000;
            eqn.n2.Charm = 5000;
            eqn.n2.Light = 5000;

            eqn.n12.Bottom = 2500;
            eqn.n12.Charm = 2500;
            eqn.n12.Light = 2500;

            eqn.p.Bottom = 10000;
            eqn.p.Charm = 10000;
            eqn.p.Light = 10000;

            eqn.p1.Bottom = 5000;
            eqn.p1.Charm = 5000;
            eqn.p1.Light = 5000;

            eqn.p2.Bottom = 5000;
            eqn.p2.Charm = 5000;
            eqn.p2.Light = 5000;

            eqn.p12.Bottom = 2500;
            eqn.p12.Charm = 2500;
            eqn.p12.Light = 2500;

            return eqn;
        }
    }
}